#pragma once
#include <zGraphicsConfig.hpp>
#include "KeyDefine.hpp"
#include "../GraphicsGUI/GraphicsGUI.hpp"
#include "../Resource/ResourceManager.hpp"
#include <Utility/Thread.hpp>

namespace zzz{
class Renderer;
class ZGRAPHICS_CLASS Context {
public:
  Context();
  virtual ~Context();

public:
  // Connect renderer and context.
  // Call this function as soon as possible.
  // Better to be called inside context initialization.
  // Do not make user to call explicitly, they will forget...
  // Do not in constructor for users' convenience
  void SetRenderer(Renderer *renderer);

  // Generally speaking, this method need not to be overrided.
  // In every paint function which is called after dirty by GUI system.
  // Should only call this RenderScene() function.
  // swapbuffer by GUI system should be disabled.
  virtual void RenderScene();

  // This make window dirty, so paint will be insert into message queue.
  virtual void Redraw()=0;

  // To swap opengl buffer.
  virtual void SwapBuffer()=0;

  // Need override, make current, for multi context.
  // ALWAYS NEED TO CALL THISl
  virtual void MakeCurrent();

  // To hide/show cursor, for camera operation.
  virtual void HideCursor(){}
  virtual void ShowCursor(){}

  // For GraphicsGUI.
  // If renderer owns the mouse, gui will not receive.
  void OwnMouse(bool own){own_mouse_=own;}
  void OwnKeyboard(bool own){own_keyboard_=own;}

  // Interface to send message to Renderer
  void OnMouseMove(unsigned int nFlags,int x,int y);
  void OnLButtonDown(unsigned int nFlags,int x,int y);
  void OnLButtonUp(unsigned int nFlags,int x,int y);
  void OnRButtonDown(unsigned int nFlags,int x,int y);
  void OnRButtonUp(unsigned int nFlags,int x,int y);
  void OnMButtonDown(unsigned int nFlags,int x,int y);
  void OnMButtonUp(unsigned int nFlags,int x,int y);
  void OnMouseWheel(unsigned int nFlags, int zDelta, int x,int y);
  void OnSize(unsigned int nType, int cx, int cy);
  void OnChar(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags);
  void OnKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags);
  void OnKeyUp(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags);
  void OnIdle();

  // Wwap renderer, since resources are connected to the context, it is not very useful.
  void SwapRenderer(Context *other);

  // Get renderer
  Renderer* GetRenderer(){return renderer_;}

  // Get resource manager
  ResourceManager* GetRM(){return &RM_;}
protected:
  bool own_mouse_;
  bool own_keyboard_;
  bool show_gui_;
  GraphicsGUI<Renderer> *gui_;
  Renderer *renderer_;
  ResourceManager RM_;
  //ATTENTION: fill the window size when resize
  int width_, height_;

public:
  static Context *current_context_;
#ifdef ZZZ_OPENGL_MX
  static Mutex OpenGLMutex;
#endif // ZZZ_OPENGL_MX
};

}
